﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GomeeSoft.src.classes;

namespace GomeeSoft.src.control
{
    public partial class UCCombo : UserControl
    {
        // Enumerations
        public enum DropDownStateEnum
        {
            Closed,
            Opening,
            Opened,
            Closing
        };

        public enum DockSideEnum
        {
            Left,
            Right
        }

        // Class Variables
        protected bool mousePressed = false;
        private bool closedWhileInControl;
        private bool designView = true;
        private Control dropDownItem;
        private DockSideEnum dockSide;
        private DropDownContainer dropContainer;
        private DropDownStateEnum dropDownState = DropDownStateEnum.Closed;
        private Rectangle anchorClientBounds;
        private Size storedSize;
        private Size anchorSize;

        // Encapsulation
        protected bool DesignView
        {
            get { return designView; }
            set { if (designView == value) return; designView = value; if (designView) Size = storedSize; else { storedSize = Size; Size = anchorSize; } }
        }
        protected DropDownStateEnum DropDownState
        {
            get { return dropDownState; }
        }
        public DockSideEnum DockSide
        {
            get { return dockSide; }
            set { dockSide = value; }
        }
        public Rectangle AnchorClientBounds
        {
            get { return anchorClientBounds; }
        }
        public Size AnchorSize
        {
            get { return anchorSize; }
            set { anchorSize = value; Invalidate(); }
        }
        public override string Text
        {
            get { return textBox1.Text; }
            set { textBox1.Text = value; Invalidate(); }
        }

        // Behavior Logic
        public UCCombo()
        {
            InitializeComponent();
            textBox1.BorderStyle = BorderStyle.None;
            textBox1.Location = new Point(3, 2);
            storedSize = Size;
            Text = Name;
        }

        public void InitializeCombo(Control dropDownItemControl)
        {
            if (dropDownItem != null)
                throw new Exception("The drop down item has already been implemented!");
            designView = false;
            dropDownState = DropDownStateEnum.Closed;
            Size = anchorSize;
            anchorClientBounds = new Rectangle(2, 2, anchorSize.Width - 21, anchorSize.Height - 4);
            if (Controls.Contains(dropDownItemControl))
                Controls.Remove(dropDownItemControl);
            dropDownItem = dropDownItemControl;
        }

        private void UCCombo_Resize(object sender, EventArgs e)
        {
            if (designView)
                storedSize = Size;
            anchorSize.Width = Width;
            if (!designView)
            {
                anchorSize.Height = Height;
                anchorClientBounds = new Rectangle(2, 2, anchorSize.Width - 21, anchorSize.Height - 4);
            }

            textBox1.Width = Width - 17;
            textBox1.Height = Height;
            pictureBox1.Left = Width - 12;
            pictureBox1.Top = textBox1.Top + (textBox1.Height - pictureBox1.Height) / 2;
            if (dropDownItem != null)
                dropDownItem.Width = Width;
        }

        private void UCCombo_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Global.GetColor(Global.UCLabelForeColor));
            Graphics graphics = e.Graphics;
            graphics.DrawLine(pen, 0, 0, 0, Height - 1);
            graphics.DrawLine(pen, Width - 1, Height - 1, 0, Height - 1);
            graphics.DrawLine(pen, Width - 1, Height - 1, Width - 1, 0);
            graphics.DrawLine(pen, 0, 0, Width - 1, 0);
            pen.Dispose();
        }

        private void UCCombo_MouseDown(object sender, MouseEventArgs e)
        {
            mousePressed = true;
            OpenDropDown();
        }

        private void UCCombo_MouseUp(object sender, MouseEventArgs e)
        {
            mousePressed = false;
        }

        protected virtual bool CanDrop
        {
            get
            {
                if (dropContainer != null)
                    return false;

                if (dropContainer == null && closedWhileInControl)
                {
                    closedWhileInControl = false;
                    return false;
                }

                return !closedWhileInControl;
            }
        }

        protected void OpenDropDown()
        {
            if (dropDownItem == null)
                throw new NotImplementedException("The drop down item has not been initialized! Use the InitializeCombo() method to do so.");

            if (!CanDrop) return;

            dropContainer = new DropDownContainer(dropDownItem);
            Rectangle r = new Rectangle(GetDropDownLocation(), new Size(dropDownItem.Width, dropDownItem.Height));

            dropContainer.Bounds = r;
            dropContainer.DropStateChange += new DropDownContainer.DropWindowArgs(dropContainer_DropStateChange);
            dropContainer.FormClosed += new FormClosedEventHandler(dropContainer_Closed);
            dropDownState = DropDownStateEnum.Opening;
            dropContainer.Show();
            dropDownState = DropDownStateEnum.Opened;
            this.Invalidate();
        }

        public void CloseDropDown()
        {
            if (dropContainer != null)
            {
                dropDownState = DropDownStateEnum.Closing;
                dropContainer.Freeze = false;
                dropContainer.Close();
            }
        }

        private void dropContainer_DropStateChange(DropDownStateEnum state)
        {
            dropDownState = state;
        }

        private void dropContainer_Closed(object sender, FormClosedEventArgs e)
        {
            if (!dropContainer.IsDisposed)
            {
                dropContainer.DropStateChange -= dropContainer_DropStateChange;
                dropContainer.FormClosed -= dropContainer_Closed;
                dropContainer.Dispose();
            }
            dropContainer = null;
            closedWhileInControl = (this.RectangleToScreen(this.ClientRectangle).Contains(Cursor.Position));
            dropDownState = DropDownStateEnum.Closed;
            this.Invalidate();
        }

        protected virtual Point GetDropDownLocation()
        {
            if (dockSide == DockSideEnum.Left)
                return this.Parent.PointToScreen(new Point(this.Bounds.X, this.Bounds.Bottom));
            return this.Parent.PointToScreen(new Point(this.Bounds.Right - dropDownItem.Width, this.Bounds.Bottom));
        }

        public event EventHandler PropertyChanged;
        protected void OnPropertyChanged()
        {
            if (PropertyChanged != null)
                PropertyChanged(null, null);
        }

        internal sealed class DropDownContainer : Form, IMessageFilter
        {
            // Class Variables
            public bool Freeze;

            public DropDownContainer(Control dropDownItem)
            {
                FormBorderStyle = FormBorderStyle.None;
                dropDownItem.Location = new Point(0, 0);
                Controls.Add(dropDownItem);
                StartPosition = FormStartPosition.Manual;
                ShowInTaskbar = false;
                Application.AddMessageFilter(this);
            }

            public bool PreFilterMessage(ref Message m)
            {
                if (!Freeze && Visible && (Form.ActiveForm == null || !Form.ActiveForm.Equals(this)))
                {
                    Close();
                }
                return false;
            }

            public delegate void DropWindowArgs(DropDownStateEnum state);
            public event DropWindowArgs DropStateChange;
            public void OnDropStateChange(DropDownStateEnum state)
            {
                if (DropStateChange != null)
                    DropStateChange(state);
            }

            protected override void OnClosing(CancelEventArgs e)
            {
                Application.RemoveMessageFilter(this);
                Controls.RemoveAt(0);
                base.OnClosing(e);
            }
        }
    }
}
